﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace elevator
{
    class car:INotifyPropertyChanged
    {
        int currentFloor=0;
        List<int> stopList = new List<int>();
        //int carStatus=2;
        //int doorStatus=2;
        sta carStatus = sta.stopping;
        doorSta doorStatus = doorSta.closed;

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
            }
        }

        /// <summary>
        /// 当前楼层
        /// </summary>
        public int CurrentFloor
        {
            get => currentFloor; set
            {
                currentFloor = value;
                OnPropertyChanged("CurrentFloor");
            }
        }
        /// <summary>
        /// 停梯列表
        /// </summary>
        public List<int> StopList { get => stopList; set => stopList = value; }
        /// <summary>
        /// 电梯运行状态
        /// </summary>
        public sta CarStatus
        {
            get => carStatus; set
            {
                carStatus = value;
                if (PropertyChanged!=null)
                {
                    string showName;
                    switch (CarStatus)
                    {
                        case sta.goUp:
                            showName = "电梯上行";
                            break;
                        case sta.goDown:
                            showName = "电梯下行";
                            break;
                        case sta.stopping:
                            showName = "电梯停止";
                            break;
                        default:
                            showName = "电梯运行状态未知";
                            break;
                    }
                    PropertyChanged(this, new PropertyChangedEventArgs(showName));
                }
                //OnPropertyChanged("CarStatus");
            }
        }
        /// <summary>
        /// 电梯门状态
        /// </summary>
        public doorSta DoorStatus
        {
            get => doorStatus; set
            {
                doorStatus = value;
                if (PropertyChanged != null)
                {
                    string showName;
                    switch (DoorStatus)
                    {
                        case doorSta.opening:
                            showName = "开门中……";
                            break;
                        case doorSta.closing:
                            showName = "关门中……";
                            break;
                        case doorSta.closed:
                            showName = "关门";
                            break;
                        case doorSta.manul:
                            showName = "手动";
                            break;
                        case doorSta.opened:
                            showName = "打开";
                            break;
                        default:
                            showName = "门状态异常";
                            break;
                    }
                    PropertyChanged(this, new PropertyChangedEventArgs(showName));
                }
                //OnPropertyChanged("DoorStatus");
            }
        }

        /// <summary>
        /// 电梯运行状态枚举
        /// </summary>
        public enum sta { goUp,goDown,stopping};
        /// <summary>
        /// 电梯门状态枚举
        /// </summary>
        public enum doorSta { opening,closing,closed,manul,opened};
        /// <summary>
        /// 电梯运动方向
        /// </summary>
        public enum movingDirection { goUp,goDown};

        Task openDoor()
        {
            var task = Task.Run(() =>
              {
                  if (DoorStatus != (int)doorSta.opening)
                  {
                      DoorStatus = (int)doorSta.opening;
                      Task.Delay(2000);
                      DoorStatus = doorSta.opened;
                  }
              });
            return task;
            
        }
        Task closeDoor()
        {
            var task = Task.Run(() =>
            {
                if (DoorStatus != doorSta.closed)
                {
                    DoorStatus = doorSta.closing;
                    Task.Delay(2000);
                    DoorStatus = doorSta.closed;
                }
            });
            return task;
        }

        public async Task pressFloorAsync(int num)
        {
            foreach (var item in stopList)
            {
                if (item==num)
                {
                    return;
                }
            }
            StopList.Add(num);
            sortList01(StopList);

            if (stopList.Count>0)
            {
                await moveCarAsync();
            }
        }
        void sortList01(List<int> list)
        {
            for (int i = 0; i < list.Count; i++)
            {
                for (int j = i; j < list.Count; j++)
                {
                    if (list[j]<list[i])
                    {
                        int temp = list[j];
                        list[j] = list[i];
                        list[i] = temp;
                    }
                }
            }
        }
        void sortList10(List<int> list)
        {
            for (int i = 0; i < list.Count; i++)
            {
                for (int j = i; j < list.Count; j++)
                {
                    if (list[j] > list[i])
                    {
                        int temp = list[j];
                        list[j] = list[i];
                        list[i] = temp;
                    }
                }
            }
        }
        async Task<Task> sleep(int sleepTime)
        {
            var task = Task.Run(() =>
            {
                Thread.Sleep(sleepTime);
            });
            return task;
        }
        async Task moveCarAsync()
        {
            await closeDoor();
            if (stopList.Count!=0&&doorStatus==doorSta.closed)
            {
                switch (CarStatus)
                {
                    //电梯上行
                    case sta.goUp:
                        for (int i = 0; i < stopList.Count; i++)
                        {
                            if (stopList[i]> CurrentFloor)
                            {
                                CarStatus = (int)sta.goUp;
                                int goUpFloorNum = stopList[i] - CurrentFloor;
                                while (goUpFloorNum != 0)
                                {
                                    await Task.Delay(5000);
                                    CurrentFloor += 1;
                                    goUpFloorNum -= 1;
                                }
                                stopList.RemoveAt(i);
                                await openDoor();
                            }
                        }
                        CarStatus = sta.stopping;
                        break;
                    //电梯下行
                    case sta.goDown:
                        for (int i = stopList.Count-1; i > 0; i--)
                        {
                            if (stopList[i] < CurrentFloor)
                            {
                                CarStatus = sta.goDown;
                                int goUpFloorNum = CurrentFloor - stopList[i];
                                while (goUpFloorNum != 0)
                                {
                                    await Task.Delay(5000);
                                    CurrentFloor -= 1;
                                    goUpFloorNum -= 1;
                                }
                                stopList.RemoveAt(i);
                                await openDoor();
                            }
                        }
                        CarStatus = sta.stopping;
                        break;
                    //电梯停止
                    case sta.stopping:
                        if (CurrentFloor > stopList[0])
                        {
                            CarStatus = sta.goDown;
                            for (int i = stopList.Count - 1; i > 0; i--)
                            {
                                if (stopList[i] < CurrentFloor)
                                {
                                    int goUpFloorNum = CurrentFloor - stopList[i];
                                    while (goUpFloorNum != 0)
                                    {
                                        await Task.Delay(5000);
                                        CurrentFloor -= 1;
                                        goUpFloorNum -= 1;
                                    }
                                    stopList.RemoveAt(i);
                                    await openDoor();
                                }
                            }
                            CarStatus = sta.stopping;
                        }
                        else if (CurrentFloor < stopList[0])
                        {
                            CarStatus = (int)sta.goUp;
                            for (int i = 0; i < stopList.Count; i++)
                            {
                                if (stopList[i] > CurrentFloor)
                                {
                                    int goUpFloorNum = stopList[i] - CurrentFloor;
                                    while (goUpFloorNum != 0)
                                    {
                                        await Task.Delay(5000);
                                        CurrentFloor += 1;
                                        goUpFloorNum -= 1;
                                    }
                                    stopList.RemoveAt(i);
                                    await openDoor();
                                }
                            }
                            CarStatus = sta.stopping;
                        }
                        break;
                    default:
                        break;
                }
            }
        }
    }
    
}
